# -*- coding: utf-8 -*-
# created on 2017/02/23
from __future__ import division
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaOptimize, BaseOptimize
from sympy import sympify, Interval, Union, simplify
from mathsolver.functions.base import BaseFunction, BaseIneqs, BasePieceFunc, BaseValue, new_latex
from mathsolver.functions.budengshi.common_opers import interval_2_ineq_list
from mathsolver.functions.hanshu.dandiaoqujian import DanDiaoQuJian
from mathsolver.functions.hanshu.qujueduizhi import QuJueDuiZhi


def get_biaodashi_from_qujian(qujian, piecefunc):
    """根据区间得到 分段函数/绝对值函数 的分段表达式"""
    # 如果是绝对值函数，将绝对值函数化简为分段函数
    if not isinstance(piecefunc, BasePieceFunc):
        abs_solver = QuJueDuiZhi().solver(piecefunc)
        piecefunc = BasePieceFunc({"var": 'x', "name": 'f', "type": "", "expression": abs_solver.output})

    if qujian.start.is_infinite and qujian.end.is_infinite:
        middle = 0
    elif qujian.start.is_infinite:
        middle = qujian.end - 0.01
    else:
        middle = qujian.start + 0.01

    func = piecefunc.expression
    for expr, qujian in func:
        if middle in qujian:
            return sympify(expr)


def fenli_qujian(inter):
    """从区间表达式中分离出单个区间，输出 [qujian1, qujian2, ...]"""
    # 如果是Interval 直接输出
    if isinstance(inter, Interval):
        return [inter]
    # 如果是 Union 分离出单个区间
    elif isinstance(inter, Union):
        return inter.args


def _analyse_qujian_ineq(ineq, qujians):
    """根据题目给定的 a < b < -1 之类的条件 和 划分开的单调区间
    将参数设为属于对应的区间"""
    # 取出 ineq 里面所有的符号，从小到大排序
    vars_og = [sympify(item) for item in ineq if item.isalpha()]
    if '>' in ineq or '>=' in ineq:
        vars_sorted = reversed(vars_og)
    else:
        vars_sorted = vars_og

    # 如果区间个数和变量个数相等，不需要筛选区间
    if len(qujians) == len(vars_sorted):
        pass
    # 否则筛选区间
    else:
        ll = len(vars_sorted)
        # 考察左端点
        leftmost, rightmost = sympify(ineq[0]), sympify(ineq[-1])
        if leftmost.is_Number:
            op_nearest = ineq[1]
            if op_nearest in ['<', '<=']:
                # 选取最大的 l 个区间
                qujians = qujians[-ll:]
            else:
                # 选取最小的 l 个区间
                qujians = qujians[:ll]
        elif rightmost.is_Number:
            op_nearest = ineq[-2]
            if op_nearest in ['<', '<=']:
                # 选取最小的 l 个区间
                qujians = qujians[:ll]
            else:
                # 选取最大的 l 个区间
                qujians = qujians[-ll:]

    return qujians, vars_sorted


class HanShuTuXiangZhuanHuaCanShuGuanXi(BaseFunction):
    """利用函数图像转化参数关系"""

    def solver(self, *args):
        func, ineq, funceq, poly = args
        up, down = DanDiaoQuJian().solver(func).output[0].value
        # 分离出单个区间
        qujians = []
        qujians.extend(fenli_qujian(up))
        qujians.extend(fenli_qujian(down))
        # 将区间从小打到排序
        qujians.sort(key=lambda x: x.start)
        # 根据 ineq 分配参数 到各个单调区间
        qujians, vars_sorted = _analyse_qujian_ineq(ineq.value, qujians)
        ineqs_eqs = []
        eqs = []
        # 将参数分别带入到单调区间中
        for var, qujian in zip(vars_sorted, qujians):
            ineqs_eqs.extend(interval_2_ineq_list(qujian, str(var)))
            f_var = get_biaodashi_from_qujian(qujian, func).subs(func.var, var)
            eqs.append(str(f_var))
        ineqs_eqs.append(eqs)

        # TODO: 检查
        max_value = MathematicaOptimize().solver(BaseOptimize(poly.value, "Maximize",
                                                              BaseIneqs(ineqs_eqs)), None).output

        min_value = MathematicaOptimize().solver(BaseOptimize(poly.value, "Minimize",
                                                              BaseIneqs(ineqs_eqs)), None).output

        max_open = False
        min_open = False

        if not max_value[-1]:
            max_open = True
        if not min_value[-1]:
            min_open = True

        max_value = simplify(max_value[0].sympify())
        min_value = simplify(min_value[0].sympify())

        res = Interval(min_value, max_value, min_open, max_open)
        self.output.append(BaseValue(res))
        self.steps.append(["", "%s 的取值范围是 %s" % (poly.printing(), new_latex(res))])
        self.label.add("利用函数图像转化参数关系")
        return self


if __name__ == '__main__':
    pass
